package com.xbongbong.pro.statistics.help;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.constant.XbbConstant;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.enums.AggTypeEnum;
import com.xbongbong.paas.enums.DateDiffTypeEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.field.ItemPoJo;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.JsonHelperUtil;
import com.xbongbong.paas.toolbox.util.RegexUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.BaseDTO;
import com.xbongbong.pro.bi.commons.pojo.AggFieldPojo;
import com.xbongbong.pro.domain.entity.ChartEntity;
import com.xbongbong.pro.service.toolbox.statistic.util.ChartResultUtil;
import com.xbongbong.pro.statistic.enums.ChartAggNameEnum;
import com.xbongbong.pro.statistic.enums.ChartAggResultEnum;
import com.xbongbong.pro.statistic.enums.ChartTypeEnum;
import com.xbongbong.pro.statistic.enums.NumFormatEnum;
import com.xbongbong.pro.statistic.help.ChartResultHelp;
import com.xbongbong.pro.statistic.pojo.BiaxialInfoPojo;
import com.xbongbong.pro.statistic.pojo.vo.DataWarningQueryListVO;
import com.xbongbong.pro.statistic.result.pojo.ChartRlWarningDataPojo;
import com.xbongbong.pro.statistic.result.pojo.ChartRlWarningPojo;
import com.xbongbong.pro.statistic.result.pojo.FieldAttrPojo;
import com.xbongbong.pro.statistic.result.pojo.vo.ChartAnalysisVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ResultDataChartVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ResultDataSeriesChartVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ScatterChartVO;
import com.xbongbong.pro.statistics.enums.BiMathEnum;
import com.xbongbong.pro.statistics.pojo.CkStatisticPojo;
import com.xbongbong.pro.statistics.pojo.dto.ChartAnalysisDTO;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.service.toolbox.help.AttrDecimalPrecisionHelper;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 图的展示帮助类
 * @ClassName ChartGraphVOhelper
 * @Author 梁鲁江
 * 创建时间 2022/9/27 19:34
 * 修改时间  2022/9/27 19:34
 **/
@Component
public class ChartGraphVOHelper {
    @Resource
    private CkResultHelp ckResultHelp;
    @Resource
    private ChartResultHelp chartResultHelp;
    @Resource
    private AttrDecimalPrecisionHelper attrDecimalPrecisionHelper;
    
    public ChartAnalysisVO chartGraphAnalysis(ChartAnalysisDTO chartAnalysisDTO, Map<String, Map<String, String>> attrLinkMap) throws XbbException {
        ChartAnalysisVO chartAnalysisVO = new ChartAnalysisVO();
        JSONObject result = new JSONObject();
        ChartEntity chartEntity = chartAnalysisDTO.getChartEntity();
        // chartValue、chartValueSecond转换成jsonObject
        ckResultHelp.transformObj(chartEntity);
        JSONArray chartValue = chartEntity.getChartValue();
        // 单表or多表数据获取
        JSONArray resultArr  = chartAnalysisDTO.getResultArray();
        JSONArray tableHead = chartAnalysisDTO.getTableHead();
        Map<String, AggFieldPojo> aggFieldMap = chartAnalysisDTO.getAggFieldMap();
        // 目前分类、系列不允许多个
        FieldAttrPojo classifyAttrPojo = null;
        FieldAttrPojo seriesAttrPojo = null;
        if (CollectionUtils.isNotEmpty(chartEntity.getChartClassify())) {
            classifyAttrPojo = JSONArray.parseArray(chartEntity.getChartClassify().toJSONString(), FieldAttrPojo.class).get(0);
        }
        if (CollectionUtils.isNotEmpty(chartEntity.getChartSeries())) {
            seriesAttrPojo = JSONArray.parseArray(chartEntity.getChartSeries().toJSONString(), FieldAttrPojo.class).get(0);
        }
        // 表头渲染
        List<JSONObject> headList = JSON.parseArray(tableHead.toJSONString(), JSONObject.class);
        result.put("customTitle", headList);
        // key为分类，目前同环比用
        Map<String, String> classifyValMap = new HashMap<>(aggFieldMap.size());
        //结果集的前置处理
        resultArr = ckResultHelp.preParseResultArray(resultArr,chartEntity,aggFieldMap);
        // sql结果集解析
        List<Map<String, CkStatisticPojo>> classifyPojoList = ckResultHelp.parseSqlResult(resultArr, aggFieldMap, classifyAttrPojo, seriesAttrPojo, classifyValMap,chartEntity);

        List<String> xAxis = new ArrayList<>();
        List<String> xAxisKeys = new ArrayList<>();
        List<String> legend = new ArrayList<>();
        List<String> legendKeys = new ArrayList<>();
        Map<String, JSONObject> jsonArrayMap = new LinkedHashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        // 封装jsonArrayMap
        addJsonArray(classifyPojoList, xAxis, legend, jsonArrayMap, result, chartEntity, xAxisKeys, legendKeys, chartAnalysisDTO, classifyValMap,resultArr,attrLinkMap);

        List<ResultDataChartVO> data = new ArrayList<>(xAxis.size());
        List<ResultDataSeriesChartVO> dataSeries = new ArrayList<>(xAxis.size());
        JSONArray chartValueSecond = chartEntity.getChartValueSecond();
        JSONArray chartValueList = new JSONArray().fluentAddAll(chartValue);
        if (CollectionUtils.isNotEmpty(chartEntity.getChartValueSecond())){
            chartValueList.addAll(chartValueSecond);
        }
        List<FieldAttrPojo> fieldAttrPojoList = JsonHelperUtil.parseArray(chartValueList.toJSONString(), FieldAttrPojo.class);
        FieldAttrPojo fieldAttrPojo = JsonHelperUtil.parseArray(chartValue.toJSONString(), FieldAttrPojo.class).get(0);
        // 如果是折线图或者柱形图查询出开启的预警查询每个预警最近的3条预警历史
        Map<String,Object> dwVoMap = chartResultHelp.getDWQueryListVO(chartAnalysisDTO,chartEntity);
        DataWarningQueryListVO dataWarningQueryListVO = null;
        if (null != dwVoMap){
            dataWarningQueryListVO = (DataWarningQueryListVO) dwVoMap.get("dataWarningQueryListVO");
        }
        if (chartEntity.getChartType().equals(ChartTypeEnum.PIE_CHART.getCode()) || chartEntity.getChartType().equals(ChartTypeEnum.MAP_CUSTOM.getCode())) {
            // 饼图和地图渲染
            chartDataSeriesRender(xAxis, legend, jsonArrayMap, result, dataSeries, fieldAttrPojo);
        } else if (chartEntity.getChartType().equals(ChartTypeEnum.FUNNEL.getCode())) {
            funnelChartDataSeriesRender(xAxis, xAxisKeys, jsonArrayMap, result, dataSeries, chartValue, chartEntity);
        } else {
            chartDataRender(chartEntity,xAxisKeys,xAxis, legendKeys, legend,jsonArrayMap, result, data, chartEntity.getBiaxial(),fieldAttrPojoList, chartValue.size(),dataWarningQueryListVO);
        }
        chartAnalysisVO.setResult(result);
        return chartAnalysisVO;
    }

    /**
     * 漏斗图封装DataSeries渲染
     *
     * @param xAxis        x轴的值
     * @param xAxisKeys    x轴的key值
     * @param jsonArrayMap 结果集
     * @param result       最终返回result集合
     * @param dataSeries   漏斗图数据（包括维度值、指标值）
     * @param chartValue   指标集合
     * @param chartEntity  图表实体
     */
    private void funnelChartDataSeriesRender(List<String> xAxis, List<String> xAxisKeys, Map<String, JSONObject> jsonArrayMap, JSONObject result, List<ResultDataSeriesChartVO> dataSeries, JSONArray chartValue, ChartEntity chartEntity) {
        JSONObject explains = chartEntity.getExplains();
        if (Objects.isNull(explains)) {
            return;
        }
        JSONObject funnel = JSON.parseObject(JSON.toJSONString(explains.get(StringConstant.FUNNEL)));
        if (Objects.isNull(funnel)) {
            return;
        }
        // transformRate为1，代表需要计算转换率
        Integer transformRate = funnel.getInteger("transformRate");
        boolean transformRateFlag = Objects.equals(BasicConstant.ONE, transformRate);
        Object selectTargetTemp = funnel.get("selectTarget");
        // selectTarget代表需要计算转换率的字段
        FieldAttrPojo selectTarget = null;
        if (Objects.nonNull(selectTargetTemp)) {
            selectTarget = JSONObject.parseObject(selectTargetTemp.toString(), FieldAttrPojo.class);
        }
        boolean selectTargetIsNull = Objects.isNull(selectTarget);
        boolean single = EsUtil.getSingle(chartEntity);
        Map<String, ResultDataSeriesChartVO> linkedHashMapMap = new LinkedHashMap<>();
        FieldAttrPojo chartClassifyPojo = JSONObject.parseObject(JSONObject.toJSONString(chartEntity.getChartClassify().get(0)), FieldAttrPojo.class);
        List<FieldAttrPojo> fieldAttrPojoList = JsonHelperUtil.parseArray(JSON.toJSONString(chartValue), FieldAttrPojo.class);
        // 前置处理一些漏斗图中的维度字段和统计的指标集合的基本信息
        getFunnelItems(linkedHashMapMap, result, chartClassifyPojo, fieldAttrPojoList, single, transformRateFlag, selectTargetIsNull, selectTarget,xAxis,xAxisKeys);
        BigDecimal totalBigDecimal = new BigDecimal("0");
        // 用来拿x轴对应的key值的，比如 1（key值） -- 发现需求（value值）
        int index = 0;
        for (String xAxisContrast : xAxis) {
            // 最外层的指标，name就是图表编辑时的维度值
            ResultDataSeriesChartVO resultDataSeriesChartVO = new ResultDataSeriesChartVO();
            resultDataSeriesChartVO.setName(xAxisContrast);
            List<ResultDataSeriesChartVO> resultDataSeriesChartVOList = new ArrayList<>();
            for (int i = 0; i < fieldAttrPojoList.size(); i++) {
                FieldAttrPojo fieldAttrPojo = fieldAttrPojoList.get(i);
                String legendContrast = fieldAttrPojo.getLabelName();
                // 字段类型code 判断是否为计数类型
                Integer fieldType = fieldAttrPojo.getFieldType();
                Integer accuracy = fieldAttrPojo.getAccuracy();
                accuracy = accuracy == null ? 2 : accuracy;
                Integer groupingUsed = fieldAttrPojo.getGroupingUsed();
                Integer numFormat = fieldAttrPojo.getNumFormat();
                NumFormatEnum numFormatEnum = NumFormatEnum.getByCode(numFormat);
                Integer percentUsed = fieldAttrPojo.getPercentUsed();
                // 用百分比，数据计算精度加两位，符号统一由前端渲染
                if (Objects.equals(percentUsed, 1)) {
                    accuracy += 2;
                }
                // 计数不需要小数
                if (fieldType.equals(FieldTypeEnum.COUNT.getType())) {
                    accuracy = 0;
                }
                JSONObject dataForm = new JSONObject();
                dataForm.put("accuracy", accuracy);
                dataForm.put("groupingUsed", groupingUsed);
                dataForm.put("percentUsed", percentUsed);
                dataForm.put("unit", numFormatEnum.getNoYuanUnit());
                double sum = 0.0;
                String value = "";
                // 内层指标，目前最多支持三个（根据legend的数量来决定个数）
                ResultDataSeriesChartVO resultDataSeriesChart = new ResultDataSeriesChartVO();
                resultDataSeriesChart.setName(legendContrast);
                // 因为漏斗图展示出来的字段名称需要前端进行特殊的拼接规则（根本因为是字段太长前端样式会有问题）
                if (Objects.equals(legendContrast, fieldAttrPojo.getLabel())) {
                    // 计算字段处理成false是因为计算字段本身就是用户自己输入的名称
                    if (Objects.equals(FieldTypeEnum.COMPUTED_FIELD.getType(), fieldType)) {
                        resultDataSeriesChart.setLabelNameEditFlag(Boolean.TRUE);
                    } else {
                        resultDataSeriesChart.setLabelNameEditFlag(Boolean.FALSE);
                    }
                } else {
                    resultDataSeriesChart.setLabelNameEditFlag(Boolean.TRUE);
                }
                resultDataSeriesChart.setDataForm(dataForm);
                // 防止多个xAxis为空字符串造成不唯一问题
                HashMap<String, Integer> legendEmptyStringMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                String key = xAxisContrast + "-" + legendContrast;
                // 此处特殊处理为了防止部门为0不返回数据 --- bug55542, 这个地方y轴的key和value使用的是一个参数是因为这是经过处理之后的
                key = specialDealKey(xAxisContrast, legendEmptyStringMap, legendContrast, key, legendContrast);
                JSONObject object = jsonArrayMap.get(key);
                if (object != null) {
                    String xAxisValue = object.getString(ChartAggResultEnum.X_AXIS.getStr());
                    if (xAxisContrast.equals(xAxisValue)) {
                        String countValue = object.getString(ChartAggResultEnum.COUNT.getStr());
                        sum += Double.parseDouble(countValue);
                    }
                }
                // 格式化
                value = StringUtil.formatDouble(sum, accuracy, 1);
                // 百分比
                if (Objects.equals(percentUsed, 1) && !"".equals(value)) {
                    value = String.valueOf(new BigDecimal(value).multiply(new BigDecimal("100")));
                }
                // 数值格式
                value = String.valueOf(ChartResultUtil.formatVal4Num(new BigDecimal(value), numFormatEnum, accuracy));
                // 漏斗图斜率选择真实 是按照指标的值 来显示大小的 现在是三个指标 默认用第一个指标的value值
                if (i == BasicConstant.ZERO) {
                    resultDataSeriesChartVO.setValue(value);
                }
                resultDataSeriesChart.setValue(value);

                // 根据单表或者多表确定需要计算转换率的字段，用resultDataSeriesChart对象的code记录需要计算转换率的字段对象
                if (transformRateFlag && !selectTargetIsNull) {
                    if (single) {
                        if (Objects.equals(selectTarget.getAttr(), fieldAttrPojo.getAttr())) {
                            resultDataSeriesChart.setCode(fieldAttrPojo.getAttr());
                            totalBigDecimal = handleFunnelValue(totalBigDecimal, selectTarget, resultDataSeriesChart, index, xAxisKeys, linkedHashMapMap);
                        }
                    } else {
                        if (Objects.equals(selectTarget.getAttr(), fieldAttrPojo.getOriginalAttr()) && Objects.equals(selectTarget.getFormId(), fieldAttrPojo.getFormId())) {
                            resultDataSeriesChart.setCode(fieldAttrPojo.getOriginalAttr());
                            totalBigDecimal = handleFunnelValue(totalBigDecimal, selectTarget, resultDataSeriesChart, index, xAxisKeys, linkedHashMapMap);
                        }
                    }
                }
                resultDataSeriesChartVOList.add(resultDataSeriesChart);
            }
            resultDataSeriesChartVO.setResultDataSeriesChartVOList(resultDataSeriesChartVOList);
            // 处理需要支持统计的阶段（也就在在表单设计中存在的阶段）
            handleLinkedHashMapMap(resultDataSeriesChartVO, linkedHashMapMap, index, xAxisKeys);
            index++;
            dataSeries.add(resultDataSeriesChartVO);
        }
        // 过滤掉不存在于表单设计中的阶段
        dataSeries = new ArrayList<>(linkedHashMapMap.values());
        if (transformRateFlag && !selectTargetIsNull) {
            // 处理转化率
            handleFunnelTransFormRate(dataSeries, totalBigDecimal, selectTarget);
        }
        result.put("dataSeries", dataSeries);
    }

    private void filterXaxisKey(List<String> xAxis, List<String> xAxisKeys, FieldAttrPojo chartClassifyPojo) {
        List<ItemPoJo> items = chartClassifyPojo.getItems();
        if (CollectionUtils.isEmpty(items)){
            //xAxisKeys，xAxis是非当前版本内的数据，则清空
            xAxis.clear();
            xAxisKeys.clear();
            return;
        }
        //取出对应xAxis中要删除的索引
        List<String> itemKeys = items.stream().map(item -> String.valueOf(item.getValue())).collect(Collectors.toList());
        List<String> removeStrList = new ArrayList<>();
        for (int i = 0; i < xAxisKeys.size(); i++) {
            if(!itemKeys.contains(xAxisKeys.get(i))){
                removeStrList.add(xAxis.get(i));
            }
        }
        //删除对应数据
        xAxis.removeIf(removeStrList::contains);
        xAxisKeys.removeIf(key -> !itemKeys.contains(key));
    }

    /**
     * 将计算好的值赋值给linkedHashMapMap，因为需要过滤掉不在表单设计中的没有的阶段的值
     *
     * @param resultDataSeriesChartVO 处理好的单个维度的指标的信息
     * @param linkedHashMapMap        需要用来过滤的map
     * @param index                   x轴key值的索引
     * @param xAxisKeys               x轴的key值
     */
    private void handleLinkedHashMapMap(ResultDataSeriesChartVO resultDataSeriesChartVO, Map<String, ResultDataSeriesChartVO> linkedHashMapMap, int index, List<String> xAxisKeys) {
        if (CollectionUtils.isNotEmpty(xAxisKeys) && xAxisKeys.size() > index) {
            String xAxisKey = xAxisKeys.get(index);
            ResultDataSeriesChartVO temp = linkedHashMapMap.get(xAxisKey);
            // 只有在表单设计中存在的阶段才需要进行统计
            if (Objects.nonNull(temp)) {
                linkedHashMapMap.put(xAxisKey, resultDataSeriesChartVO);
            }
        }
    }

    /**
     * jsonArray结果集 组装
     *
     * @param ckStatisticsPojoList 聚合结果集
     * @param xAxis                   X轴-分类
     * @param legend                  y轴-系列
     * @param jsonArrayMap            结果集
     * @param result                  最终返回result集合
     * @param chartEntity             图表实体
     * @param xAxisKeys               x轴分类key存储
     * @param legendKeys              y轴系列key存储
     * @param baseDTO                 基础dto
     * @param classifyValMap          key为分类的map，同环比用
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2021/11/5 10:15
     * @version 1.0
     */
    private void addJsonArray(List<Map<String, CkStatisticPojo>> ckStatisticsPojoList, List<String> xAxis, List<String> legend, Map<String, JSONObject> jsonArrayMap, JSONObject result, ChartEntity chartEntity, List<String> xAxisKeys, List<String> legendKeys, BaseDTO baseDTO, Map<String, String> classifyValMap, JSONArray resultArr, Map<String, Map<String, String>> attrLinkMap) throws XbbException {
        JSONObject xAxisObject = chartEntity.getChartClassify().getJSONObject(0);
        FieldAttrPojo xAxisAttr = JSONObject.parseObject(xAxisObject.toJSONString(), FieldAttrPojo.class);
        JSONArray chartSeriesArray = chartEntity.getChartSeries();
        JSONObject legendObject = new JSONObject();
        if (chartSeriesArray != null && chartSeriesArray.size() > 0) {
            legendObject = chartEntity.getChartSeries().getJSONObject(0);
        }
        FieldAttrPojo legendAttr = JSONObject.parseObject(legendObject.toJSONString(), FieldAttrPojo.class);
        String corpId = chartEntity.getCorpid();
        JSONArray chartValue = new JSONArray(chartEntity.getChartValue());
        JSONArray chartValueSecond = chartEntity.getChartValueSecond();
        JSONArray chartValueList = new JSONArray().fluentAddAll(chartValue);
        JSONArray jsonArray = new JSONArray();
        // 计算字段，日期公式时标题legend回显需要
        Map<String,String> computedDateDiffMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (Map<String, CkStatisticPojo> ckStatisticPojoMap : ckStatisticsPojoList) {
            CkStatisticPojo ckStatisticPojo = ckStatisticPojoMap.get(ChartAggNameEnum.AGG_FIRST.getStr());
            String classifyValue = ckStatisticPojo.getValue();
            xAxisKeys.add(classifyValue);
            List<Map<String, CkStatisticPojo>> legendList = ckStatisticPojo.getSub();
            if (legendList != null && legendList.size() > 0) {
                Collections.sort(legendList, (o1, o2) -> {
                    Set<String> p1Set = o1.keySet();
                    Set<String> p2Set = o2.keySet();
                    String p1Key;
                    String p2Key;
                    if (Objects.isNull(p1Set) || Objects.isNull(p2Set)){
                        return 1;
                    } else {
                        p1Key = new ArrayList<>(p1Set).get(0);
                        p2Key = new ArrayList<>(p2Set).get(0);
                        int p1EndIndex = 0;
                        int p2EndIndex = 0;
                        if (((p1EndIndex = p1Key.lastIndexOf("&")) != -1) && ((p2EndIndex = p2Key.lastIndexOf("&")) != -1)){
                            String p1Sort = p1Key.substring(p1EndIndex+1);
                            String p2Sort = p2Key.substring(p2EndIndex+1);
                            return p1Sort.compareTo(p2Sort);
                        }
                        return 1;
                    }
                });
                for (Map<String, CkStatisticPojo> chartLegend : legendList) {
                    //存在agg2，则为三层聚合
                    if (chartLegend.containsKey(ChartAggNameEnum.AGG_SECOND.getStr())) {
                        JSONObject agg2Object = new JSONObject();
                        CkStatisticPojo chartAgg2 = chartLegend.get(ChartAggNameEnum.AGG_SECOND.getStr());
                        String legendValue = chartAgg2.getValue();
                        if (!legendKeys.contains(legendValue)) {
                            legendKeys.add(legendValue);
                        }
                        List<Map<String, CkStatisticPojo>> subList = chartAgg2.getSub();
                        if (CollectionUtils.isEmpty(subList)){
                            continue;
                        }
                        for (Map<String, CkStatisticPojo> sub : subList) {
                            // 有分类有系列目前只支持单指标
                            FieldAttrPojo valueAttrPojo = JSONObject.parseObject(JSON.toJSONString(chartValue.get(0)), FieldAttrPojo.class);
                            CkStatisticPojo chartPojo;
                            String key = ChartAggNameEnum.SUM_TOTAL.getStr() + "&" + valueAttrPojo.getFormId() + "&" + valueAttrPojo.getAttr() + "&" + PaasConstant.LEFT + "&" + "0";
                            if (sub.containsKey(key)) {
                                chartPojo = sub.get(key);
                                String value = chartPojo.getValue();
                                // 同环比处理
                                value = getYearChainVal4Chart(classifyValMap, xAxisAttr, classifyValue, value, valueAttrPojo, key);
                                agg2Object.put(ChartAggResultEnum.COUNT.getStr(), value);
                            }
                            agg2Object.put(ChartAggResultEnum.X_AXIS.getStr(), classifyValue);
                            agg2Object.put(ChartAggResultEnum.LEGEND.getStr(), legendValue);
                            jsonArray.add(agg2Object);
                            if(Objects.equals(ChartTypeEnum.SCATTER_CHART.getCode(),chartEntity.getChartType()) && chartValueList.size() == 2){
                                Map<String, CkStatisticPojo> ckStatisticPojoMap2 = subList.get(1);
                                FieldAttrPojo valueAttrPojo2 = JSONObject.parseObject(JSON.toJSONString(chartValue.get(1)), FieldAttrPojo.class);
                                CkStatisticPojo chartPojo2;
                                String key2 = ChartAggNameEnum.SUM_TOTAL.getStr() + "&" + valueAttrPojo2.getFormId() + "&" + valueAttrPojo2.getAttr() + "&" + PaasConstant.LEFT + "&" + "1";
                                if (ckStatisticPojoMap2.containsKey(key2)) {
                                    chartPojo2 = ckStatisticPojoMap2.get(key2);
                                    String value = chartPojo2.getValue();
                                    // 同环比处理
                                    value = getYearChainVal4Chart(classifyValMap, xAxisAttr, classifyValue, value, valueAttrPojo2, key2);
                                    agg2Object.put(ChartAggResultEnum.SCATTER_SIZE.getStr(), value);
                                }
                                break;
                            }
                        }
                    } else {
                        JSONObject aggObject = new JSONObject();
                        // 两层聚合情况
                        for (Map.Entry<String, CkStatisticPojo> entry : chartLegend.entrySet()) {
                            String k = entry.getKey();
                            if (!k.contains(ChartAggNameEnum.SUM_TOTAL.getStr())) {
                                continue;
                            }
                            //2层聚合情况下chartValue值(字段名)作为系列
                            CkStatisticPojo chartPojo = entry.getValue();
                            String value = chartPojo.getValue();
                            //chartValue值(字段名)
                            String attrSum = "";
                            String suffix = "";
                            for (int i = 0; i < chartValueList.size(); i++) {
                                Object item = chartValueList.get(i);
                                JSONObject jsonObject = item instanceof JSONObject ? (JSONObject) item : new JSONObject();
                                FieldAttrPojo valueAttrPojo = JSONObject.parseObject(jsonObject.toJSONString(), FieldAttrPojo.class);
                                String key = ChartAggNameEnum.SUM_TOTAL.getStr() + "&" + valueAttrPojo.getFormId() + "&" + valueAttrPojo.getAttr() + "&" + PaasConstant.LEFT + "&" + i;
                                if (k.equals(key)) {
                                    attrSum = valueAttrPojo.getLabelName() + "&" + PaasConstant.LEFT;
                                    suffix = getSuffix(jsonObject);
                                    // 同环比处理
                                    value = getYearChainVal4Chart(classifyValMap, xAxisAttr, classifyValue, value, valueAttrPojo, key);
                                    break;
                                }
                            }
                            if (CollectionUtils.isNotEmpty(chartValueSecond)) {
                                for (int i = 0; i < chartValueSecond.size(); i++) {
                                    Object item = chartValueSecond.get(i);
                                    JSONObject jsonObject = item instanceof JSONObject ? (JSONObject) item : new JSONObject();
                                    FieldAttrPojo valueAttrPojo = JSONObject.parseObject(jsonObject.toJSONString(), FieldAttrPojo.class);
                                    String key = ChartAggNameEnum.SUM_TOTAL.getStr() + "&" + jsonObject.getLong("formId") + "&" + jsonObject.getString("attr") + "&" + PaasConstant.RIGHT + "&" + (i + chartValueList.size());
                                    if (k.equals(key)) {
                                        attrSum = jsonObject.getString("labelName") + "&" + PaasConstant.RIGHT;
                                        suffix = getSuffix(jsonObject);
                                        // 同环比处理
                                        value = getYearChainVal4Chart(classifyValMap, xAxisAttr, classifyValue, value, valueAttrPojo, key);
                                        break;
                                    }
                                }
                            }
                            if (StringUtil.isEmpty(attrSum)) {
                                continue;
                            }
                            if (!legendKeys.contains(attrSum)) {
                                legendKeys.add(attrSum);
                                if (StringUtil.isNotEmpty(suffix)){
                                    computedDateDiffMap.put(attrSum,suffix);
                                }
                            }
                            aggObject.put(ChartAggResultEnum.X_AXIS.getStr(), classifyValue);
                            aggObject.put(ChartAggResultEnum.LEGEND.getStr(), attrSum);
                            aggObject.put(ChartAggResultEnum.COUNT.getStr(), value);
                            jsonArray.add(aggObject);
                        }
                        if(Objects.equals(ChartTypeEnum.SCATTER_CHART.getCode(),chartEntity.getChartType()) && chartValueList.size() == 2){
                            //散点图 - 设置气泡大小，未设置气泡颜色
                            for (Map.Entry<String, CkStatisticPojo> ckStatisticPojoEntry : legendList.get(1).entrySet()) {
                                String entryKey = ckStatisticPojoEntry.getKey();
                                for (int i = 0; i < chartValueList.size(); i++) {
                                    Object item = chartValueList.get(i);
                                    JSONObject jsonObject = item instanceof JSONObject ? (JSONObject) item : new JSONObject();
                                    FieldAttrPojo valueAttrPojo = JSONObject.parseObject(jsonObject.toJSONString(), FieldAttrPojo.class);
                                    String key = ChartAggNameEnum.SUM_TOTAL.getStr() + "&" + valueAttrPojo.getFormId() + "&" + valueAttrPojo.getAttr() + "&" + PaasConstant.LEFT + "&" + i;
                                    if (entryKey.equals(key)) {
                                        CkStatisticPojo entryValue = ckStatisticPojoEntry.getValue();
                                        // 同环比处理
                                        String scatterSize = getYearChainVal4Chart(classifyValMap, xAxisAttr, classifyValue, entryValue.getValue(), valueAttrPojo, key);
                                        aggObject.put(ChartAggResultEnum.SCATTER_SIZE.getStr(),scatterSize);
                                        break;
                                    }
                                }
                            }
                            break;
                        }
                    }
                }
            }
        }
        //系列字段为下拉类型时手动调整legendKeys的顺序
        if(CollectionUtils.isNotEmpty(chartSeriesArray) && FieldTypeEnum.isReOrder4Combo(legendAttr.getFieldType())){
            legendKeys = chartResultHelp.reOrderSeries(legendKeys,legendAttr);
        }
        // x轴去重
        Set<String> linkedHashSet = new LinkedHashSet<>(xAxisKeys);
        xAxisKeys.clear();
        xAxisKeys.addAll(linkedHashSet);
        // 解析
        Map<String, String> xAxisValueMap = valueListAnalysis(xAxisAttr, corpId, xAxisKeys, chartEntity, baseDTO,attrLinkMap);
        xAxisKeys.forEach(str -> {
            String xAxisResult = Objects.equals(null, xAxisValueMap.get(str)) ? "" : chartResultHelp.analysisResultValue(xAxisValueMap,str,xAxisAttr);
            xAxis.add(xAxisResult);
        });
        Map<String, String> legendValueMap = valueListAnalysis(legendAttr, corpId, legendKeys, chartEntity, baseDTO,attrLinkMap);
        List<String> legendTempKeys = new ArrayList<>();
        legendKeys.forEach(str -> {
            String legendResult = Objects.equals(null, legendValueMap.get(str)) ? "" : chartResultHelp.analysisResultValue(legendValueMap,str,legendAttr);
            int endIndex = 0;
            String suffix = null != computedDateDiffMap.get(str) ? computedDateDiffMap.get(str) : "";
            if (((endIndex = legendResult.lastIndexOf(XbbConstant.AMPERSAND)) != -1) && ((endIndex = legendResult.lastIndexOf(XbbConstant.AMPERSAND,endIndex)) != -1)){
                legendTempKeys.add(str.substring(0,endIndex) + suffix);
                legendResult = legendResult.substring(0,endIndex) + suffix;
            }
            legend.add(legendResult);
        });
        if (CollectionUtils.isNotEmpty(legendTempKeys)){
            legendKeys = legendTempKeys;
        }

        // 防止多个xAxis为空字符串造成不唯一问题
        HashMap<String,Integer> legendKeyEmptyStringMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            String xAxisKey = jsonObject.getString("xAxis");
            String legendKey = jsonObject.getString("legend");
            String xAxisValue = xAxisValueMap.get(xAxisKey);
            String legendValue = legendValueMap.get(legendKey);
            legendValue = Objects.equals(legendValue, null) ? "" : legendValue;
            int endIndex = 0;
            if (((endIndex = legendValue.lastIndexOf("&")) != -1) && ((endIndex = legendValue.lastIndexOf("&",endIndex)) != -1)){
                legendValue = legendValue.substring(0,legendValue.lastIndexOf("&"));
            }
            xAxisValue = Objects.equals(xAxisValue, null) ? "" : xAxisValue;
            jsonObject.put("xAxis", xAxisValue);
            if (Objects.equals(AggTypeEnum.COUNT.getName(), legendKey)) {
                legendValue = legendKey;
            }
            jsonObject.put("legend", legendValue);
            String key = xAxisValue + "-" + legendValue;
            key = specialDealKey(xAxisValue, legendKeyEmptyStringMap, legendKey, key, legendValue);
            jsonArrayMap.put(key, jsonObject);
        }
        result.put("xAxis", xAxis);
        result.put("legend", legend);
        result.put("legendKeys", legendKeys);
        result.put("xAxisKeys", xAxisKeys);
        if(Objects.equals(ChartTypeEnum.SCATTER_CHART.getCode(),chartEntity.getChartType())){
            //设置鼠标悬浮时的 x轴/系列 的字段名
            if (chartSeriesArray != null && chartSeriesArray.size() > 0) {
                result.put("legendName",legendAttr.getLabelName());
            }
            result.put("xAxisName",xAxisAttr.getLabelName());
        }
    }

    /**
     * 防止多个xAxis为空字符串造成不唯一问题，特殊处理key的值，以免取值的时候拿key获取不到数据
     *
     * @param xAxisValue              x轴的value值
     * @param legendKeyEmptyStringMap 防止多个xAxis为空字符串的map集合数据， key：y轴的值    value：第几个空值（就相当于索引）
     * @param legendKey               y轴的key值
     * @param key                     取结果值的key，在jsonArrayMap中取结果用的
     * @param legendValue             y轴的value值
     * @return 取结果值的key，在jsonArrayMap中取结果用的，为空时需要特殊处理
     */
    private String specialDealKey(String xAxisValue, HashMap<String, Integer> legendKeyEmptyStringMap, String legendKey, String key, String legendValue) {
        if ("".equals(xAxisValue)) {
            Integer emptyStringIndex = legendKeyEmptyStringMap.get(legendKey);
            if (Objects.nonNull(emptyStringIndex)) {
                key = "&" + ++emptyStringIndex + "-" + legendValue;
                legendKeyEmptyStringMap.put(legendKey, emptyStringIndex);
            } else {
                key = "&" + 0 + "-" + legendValue;
                legendKeyEmptyStringMap.put(legendKey, 0);
            }

        }
        return key;
    }


    /**
     * dataSeries组装
     *
     * @param xAxis         系列（饼图分类作为系列）
     * @param legend        系列
     * @param jsonArrayMap  结果集
     * @param result        最终返回result集合
     * @param dataSeries    饼图、环图、仪表盘、地图、漏斗等类型图的结果数据
     * @param fieldAttrPojo 字段属性实体
     * @author zhouwq
     * @date 2019/4/12 10:25
     */
    private void chartDataSeriesRender(List<String> xAxis,List<String> legend, Map<String, JSONObject> jsonArrayMap, JSONObject result, List<ResultDataSeriesChartVO> dataSeries, FieldAttrPojo fieldAttrPojo) {
        // 字段类型code 判断是否为计数类型
        Integer fieldType = fieldAttrPojo.getFieldType();
        Integer accuracy = fieldAttrPojo.getAccuracy();
        accuracy = accuracy == null ? 2 : accuracy;
        Integer groupingUsed = fieldAttrPojo.getGroupingUsed();
        Integer numFormat = fieldAttrPojo.getNumFormat();
        NumFormatEnum numFormatEnum = NumFormatEnum.getByCode(numFormat);
        Integer percentUsed = fieldAttrPojo.getPercentUsed();
        // 用百分比，数据计算精度加两位，符号统一由前端渲染
        if (Objects.equals(percentUsed, 1)) {
            accuracy += 2;
        }
        // 计数不需要小数
        if (fieldType.equals(FieldTypeEnum.COUNT.getType())) {
            accuracy = 0;
        }
        JSONObject dataForm = new JSONObject();
        dataForm.put("accuracy", accuracy);
        dataForm.put("groupingUsed", groupingUsed);
        dataForm.put("percentUsed", percentUsed);
        dataForm.put("unit", numFormatEnum.getNoYuanUnit());
        // 防止多个xAxis为空字符串造成不唯一问题
        HashMap<String,Integer> legendEmptyStringMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (String xAxisContrast : xAxis) {
            double sum = 0.0;
            String value = "";
            for (String legendContrast : legend) {
                String key = xAxisContrast + "-" + legendContrast;
                // 此处特殊处理为了防止部门为0不返回数据 --- bug55542, 这个地方y轴的key和value使用的是一个参数是因为这是经过处理之后的
                key = specialDealKey(xAxisContrast, legendEmptyStringMap, legendContrast, key, legendContrast);
                JSONObject object = jsonArrayMap.get(key);
                if (object != null) {
                    String xAxisValue = object.getString(ChartAggResultEnum.X_AXIS.getStr());
                    if (xAxisContrast.equals(xAxisValue)) {
                        String countValue = object.getString(ChartAggResultEnum.COUNT.getStr());
                        sum += Double.parseDouble(countValue);
                    }
                }
                ResultDataSeriesChartVO resultDataSeriesChartVO = new ResultDataSeriesChartVO();
                resultDataSeriesChartVO.setName(xAxisContrast);
                // 格式化
                value = StringUtil.formatDouble(sum, accuracy, 1);
                // 百分比
                if (Objects.equals(percentUsed, 1) && !"".equals(value)) {
                    value = String.valueOf(new BigDecimal(value).multiply(new BigDecimal("100")));
                }
                // 数值格式
                value = String.valueOf(ChartResultUtil.formatVal4Num(new BigDecimal(value), numFormatEnum, accuracy));
                resultDataSeriesChartVO.setValue(value);
                dataSeries.add(resultDataSeriesChartVO);
            }
        }
        result.put("dataSeries", dataSeries);
        result.put("dataForm", dataForm);

    }

    /**
     * data组装
     *
     * @param xAxis         分类
     * @param legend        系列
     * @param jsonArrayMap  结果集
     * @param result        最终返回result集合
     * @param data          折线、面积、柱形图、叠加图、雷达等类型图的结果数据
     * @author zhouwq
     * @date 2019/4/12 10:25
     */
    private void chartDataRender(ChartEntity chartEntity,List<String> xAxisKeys,List<String> xAxis, List<String> legendKeys,List<String> legend, Map<String, JSONObject> jsonArrayMap, JSONObject result, List<ResultDataChartVO> data, JSONObject biaxialInfo, List<FieldAttrPojo> fieldAttrPojoList, int chartValueSize,DataWarningQueryListVO dataWarningQueryListVO) {
        Integer chartType = chartEntity.getChartType();
        BiaxialInfoPojo biaxialInfoPojo = null;
        if (Objects.nonNull(biaxialInfo)){
            biaxialInfoPojo = JSON.parseObject(biaxialInfo.toJSONString(),BiaxialInfoPojo.class);
        }
        // 数据预警返回的数据不为null(历史预警)
        Map<String,List<ChartRlWarningPojo>> legendRlWarningMap = chartResultHelp.getLegendRlWarningMap(dataWarningQueryListVO,chartEntity,xAxisKeys);
        if (Objects.nonNull(legendRlWarningMap) && legendRlWarningMap.size()>0){
            // 是否是三层聚合
            boolean flag = true;
            for (String s : legendKeys) {
                flag = !s.contains("&" + PaasConstant.LEFT) && !s.contains("&" + PaasConstant.RIGHT);
                if (!flag){
                    break;
                }
            }
            if (flag){
                Map<String,List<ChartRlWarningPojo>> tempMap = new HashMap<>(legendRlWarningMap.size());
                for (Map.Entry<String, List<ChartRlWarningPojo>> entry : legendRlWarningMap.entrySet()) {
                    String k = entry.getKey();
                    List<ChartRlWarningPojo> v = entry.getValue();
                    k = k.replaceAll("&"+ PaasConstant.LEFT ,"");
                    tempMap.put(k,v);
                }
                legendRlWarningMap = tempMap;
            }
        }
        int index = 0;
        JSONObject dataForm = null;
        Map<String,Integer> legendEmptyStringMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        //散点图 - 设置了气泡大小时在这里需要删除气泡大小的查询设置
        FieldAttrPojo removeFieldAttrPojo = null;
        if(Objects.equals(ChartTypeEnum.SCATTER_CHART.getCode(),chartEntity.getChartType()) && fieldAttrPojoList.size() == 2){
            removeFieldAttrPojo = fieldAttrPojoList.remove(fieldAttrPojoList.size() - 1);
        }
        for (int i = 0; i < legend.size(); i++) {
            String legendContrast = legend.get(i);
            String legendKey = legendKeys.size() > i ? legendKeys.get(i) : legendContrast;
            JSONArray legendArr = new JSONArray();
            JSONArray scatterSizeArr= new JSONArray();
            index = Math.min(i, (fieldAttrPojoList.size() - 1));
            FieldAttrPojo fieldAttrPojo = fieldAttrPojoList.get(index);
            Integer fieldType = fieldAttrPojo.getFieldType();
            int accuracy = fieldAttrPojo.getAccuracy() == null ? 0 : fieldAttrPojo.getAccuracy();
            Integer groupingUsed = fieldAttrPojo.getGroupingUsed();
            Integer numFormat = fieldAttrPojo.getNumFormat();
            NumFormatEnum numFormatEnum = NumFormatEnum.getByCode(numFormat);
            String noYuanUnit = numFormatEnum.getNoYuanUnit();
            Integer percentUsed = fieldAttrPojo.getPercentUsed();
            // 用百分比，数据计算精度加两位，符号统一由前端渲染
            if (Objects.equals(percentUsed, 1)) {
                accuracy += 2;
            }
            // 计数不需要小数
            if (fieldType.equals(FieldTypeEnum.COUNT.getType())) {
                accuracy = 0;
            }
            JSONObject dataFormSingle = new JSONObject();
            dataFormSingle.put("accuracy", accuracy);
            dataFormSingle.put("groupingUsed", groupingUsed);
            dataFormSingle.put("percentUsed", percentUsed);
            dataFormSingle.put("unit", noYuanUnit);
            // 当前系列当前预警对应的预警值（当前预警）
            Map<Long,ChartRlWarningPojo> warningIdWarningPojoMap = new HashMap<>();
            for (int j = 0; j < xAxis.size(); j++) {
                String key = xAxis.get(j);
                if ("".equals(key)){
                    Integer emptyStringIndex = legendEmptyStringMap.get(legendKey);
                    if (Objects.nonNull(emptyStringIndex)){
                        key = "&" + ++emptyStringIndex;
                        legendEmptyStringMap.put(legendKey,emptyStringIndex);
                    }else {
                        key = "&" + 0;
                        legendEmptyStringMap.put(legendKey,0);
                    }

                }
                //将X轴和Y轴的key组装作为 唯一主键key
                JSONObject object = jsonArrayMap.get(key + "-" + DateDiffTypeEnum.removeSuffix(legendContrast));
                String scatterSize = "0";
                if (object != null) {
                    String countValue = "";
                    String value;
                    try {
                        countValue = object.getString(ChartAggResultEnum.COUNT.getStr());
                        value = StringUtil.formatDouble(Double.valueOf(countValue), accuracy, 1);
                        // 百分比
                        if (Objects.equals(percentUsed, 1) && !"".equals(value)) {
                            value = String.valueOf(new BigDecimal(value).multiply(new BigDecimal("100")));
                        }
                        // 数值格式
                        value = String.valueOf(ChartResultUtil.formatVal4Num(new BigDecimal(value), numFormatEnum, accuracy));
                        // 获取单表当前预警
                        warningIdWarningPojoMap = chartResultHelp.getBLWarning(dataWarningQueryListVO,chartEntity,j,warningIdWarningPojoMap,value,fieldAttrPojo);
                        // 格式化小数位
                        value = StringUtil.formatDouble(Double.valueOf(value), accuracy, 1);
                    } catch (Exception e) {
                        value = countValue;
                    }
                    legendArr.add(value);
                    scatterSize = object.getString(ChartAggResultEnum.SCATTER_SIZE.getStr());
                } else {
                    // 获取单表当前预警
                    warningIdWarningPojoMap = chartResultHelp.getBLWarning(dataWarningQueryListVO,chartEntity,j,warningIdWarningPojoMap,"0",fieldAttrPojo);
                    // 赋默认值
                    legendArr.add("0");
                }
                //如果是散点图，并且设置了气泡大小字段
                if(Objects.nonNull(removeFieldAttrPojo)){
                    ScatterChartVO scatterChartVO = new ScatterChartVO();
                    setScatterChartValue(removeFieldAttrPojo,scatterChartVO,scatterSize);
                    scatterSizeArr.add(scatterChartVO);
                }
            }
            //不存在系列
            if(CollectionUtils.isEmpty(chartEntity.getChartSeries())){
                //回显字段拼接同环比后缀
                legendContrast += ckResultHelp.splicingSuffix(fieldAttrPojo.getAdvancedComputing(),ChartTypeEnum.getByCode(chartType));
                legend.set(i,legendContrast);
            }
            ResultDataChartVO resultDataChartVO = new ResultDataChartVO(legendContrast, null, legendArr);

            // 有历史预警加上历史预警
            if (Objects.nonNull(legendRlWarningMap.get(legendKey))){
                Set<Long> set = new HashSet<>();
                set.addAll(warningIdWarningPojoMap.keySet());

                if (warningIdWarningPojoMap.size()>0){
                    Map<Long, ChartRlWarningPojo> finalWarningIdWarningPojoMap = warningIdWarningPojoMap;
                    legendRlWarningMap.get(legendKey).forEach(item ->{
                        item.setData(new ArrayList<ChartRlWarningDataPojo>(){{
                            addAll(item.getData());
                            ChartRlWarningPojo pojo = finalWarningIdWarningPojoMap.get(item.getId());
                            if (Objects.nonNull(pojo)){
                                addAll(pojo.getData());
                            }
                        }});
                        set.remove(item.getId());
                    });
                }
                Map<Long, ChartRlWarningPojo> finalWarningIdWarningPojoMap = warningIdWarningPojoMap;
                Map<String, List<ChartRlWarningPojo>> finalLegendRlWarningMap = legendRlWarningMap;
                set.forEach(item -> finalLegendRlWarningMap.get(legendKey).add(finalWarningIdWarningPojoMap.get(item)));
                resultDataChartVO.setWarningValues(JSON.parseArray(JSON.toJSONString(legendRlWarningMap.get(legendKey))));
            }else {
                // 没有历史预警直接用当前预警
                if (warningIdWarningPojoMap.size()>0){
                    List<ChartRlWarningPojo> chartRlWarningPojos = new ArrayList<>();
                    warningIdWarningPojoMap.forEach((k,v) -> chartRlWarningPojos.add(v));
                    resultDataChartVO.setWarningValues(JSON.parseArray(JSON.toJSONString(chartRlWarningPojos)));
                }
            }
            if (Objects.nonNull(biaxialInfoPojo)){
                if (index < chartValueSize ){
                    if (Objects.equals(chartType,ChartTypeEnum.BIAXIAL_CHART.getCode())){
                        resultDataChartVO.setChartType(biaxialInfoPojo.getLeftChartType());
                    }else {
                        resultDataChartVO.setChartType(chartType);
                    }
                    String leftName = biaxialInfoPojo.getLeftName();
                    StringBuilder builder = new StringBuilder(leftName);
                    builder.insert(0, noYuanUnit);
                    resultDataChartVO.setYAxisName(builder.toString());
                    resultDataChartVO.setYAxisIndex(0);
                }else {
                    if (Objects.equals(chartType,ChartTypeEnum.BIAXIAL_CHART.getCode())){
                        resultDataChartVO.setChartType(biaxialInfoPojo.getRightChartType());
                    }else {
                        resultDataChartVO.setChartType(chartType);
                    }
                    String rightName = biaxialInfoPojo.getRightName();
                    StringBuilder builder = new StringBuilder(rightName);
                    builder.insert(0, noYuanUnit);
                    resultDataChartVO.setYAxisName(builder.toString());
                    resultDataChartVO.setYAxisIndex(1);
                }
            }
            // 设置千分符和百分比
            resultDataChartVO.setDataForm(dataFormSingle);
            if (Objects.isNull(dataForm)){
                dataForm = dataFormSingle;
            }
            resultDataChartVO.setFormId(fieldAttrPojo.getFormId());
            resultDataChartVO.setAttr(fieldAttrPojo.getAttr());
            resultDataChartVO.setOriginAttr(fieldAttrPojo.getOriginalAttr());
            //散点图
            if(Objects.equals(ChartTypeEnum.SCATTER_CHART.getCode(),chartEntity.getChartType())){
                resultDataChartVO.setValueName(fieldAttrPojo.getLabelName());
                //并且设置了气泡大小
                if(Objects.nonNull(removeFieldAttrPojo)){
                    resultDataChartVO.setScatterSizeList(scatterSizeArr);
                }
            }
            data.add(resultDataChartVO);
        }
        result.put("data", data);
        result.put("dataForm", dataForm);
    }

    /**
     * 获取同环比值-统计图
     * @param classifyValMap key:拼接key+分类值，value:统计值
     * @param xAxisAttrPojo 分类pojo
     * @param classifyValue 分类值
     * @param value 统计值
     * @param valueAttrPojo 统计值pojo
     * @param key 拼接key
     * @return java.lang.String
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2021/11/29 19:14
     * @version 1.0
     */
    private String getYearChainVal4Chart(Map<String, String> classifyValMap, FieldAttrPojo xAxisAttrPojo, String classifyValue, String value, FieldAttrPojo valueAttrPojo, String key) {
        JSONArray advancedComputing = valueAttrPojo.getAdvancedComputing();
        boolean isYearChain = chartResultHelp.isYearChain4Date(xAxisAttrPojo, advancedComputing);
        if (isYearChain) {
            String oldVal = getOldValue4Chart(xAxisAttrPojo, advancedComputing, Long.parseLong(classifyValue), classifyValMap, key);
            value = chartResultHelp.getYearChainValue(valueAttrPojo, oldVal, value);
        }
        return value;
    }

    /**
     * 获取同环比差值-统计图
     * @param rowGroupAttrPojo 分组字段
     * @param advancedComputing 高级计算
     * @param nowTimestamp 当前值时间戳
     * @param classifyValMap key:拼装好的key+分类值，value:统计值
     * @param key 拼装好的key
     * @return java.lang.String 旧值
     * @author xinpeng.jiang
     * @date 2021/11/25 10:46
     * @version 1.0
     */
    private String getOldValue4Chart(FieldAttrPojo rowGroupAttrPojo, JSONArray advancedComputing, Long nowTimestamp, Map<String, String> classifyValMap, String key) {
        String oldVal = "0";
        // 计算差值时间戳
        Long oldTimestamp = ckResultHelp.getYearChainDiff(rowGroupAttrPojo, advancedComputing, nowTimestamp);
        // 去map中拿旧值，拿不到就是0
        String value = classifyValMap.get(key + "&" + oldTimestamp.toString());
        if (StringUtil.isNotEmpty(value)) {
            oldVal = value;
        }
        return oldVal;
    }

    private String getSuffix(JSONObject jsonObject){
        FieldAttrPojo fieldAttrPojo = JSONObject.toJavaObject(JSONObject.parseObject(JSONObject.toJSONString(jsonObject)),FieldAttrPojo.class);
        if(Objects.equals(fieldAttrPojo.getFieldType(), FieldTypeEnum.COMPUTED_FIELD.getType())){
            String formula = fieldAttrPojo.getFormulaInfo().getString("formula");
            String formulaName = RegexUtil.extractFormulaName(formula);
            if (Objects.equals(formulaName, BiMathEnum.DATE_DIFF.getFormula())){
                String unit = DateDiffTypeEnum.DAY.getAlias();
                String textTemp = formula.substring(1,formula.length()-1);
                int startIndex;
                if (textTemp.lastIndexOf("}") < (startIndex = textTemp.lastIndexOf(XbbConstant.SQL_COMMA))){
                    unit = textTemp.substring(startIndex);
                }
                DateDiffTypeEnum typeEnum = DateDiffTypeEnum.getByAlias(unit);
                String suffix = typeEnum.getName();
                if (StringUtil.isNotEmpty(suffix)){
                    suffix = "(" + suffix + ")";
                }
                return suffix;
            }
        }
        return "";
    }

    private Map<String, String> valueListAnalysis(FieldAttrPojo field, String corpId, List<String> values, ChartEntity chartEntity, BaseDTO baseDTO,Map<String, Map<String, String>> attrLinkMap) throws XbbException{
        return ckResultHelp.valueListAnalysis(field, corpId, values, chartEntity, true, null, true, baseDTO,null,attrLinkMap);
    }


    /**
     * 前置处理漏斗图的基本返回信息
     *
     * @param linkedHashMapMap   关联表单设计阶段推进器的具体信息，也是根据这个值来构造返回值的. key: 对应x轴的key值， value：对应每一个维度的指标值
     * @param chartClassifyPojo  维度的值
     * @param fieldAttrPojoList  指标的值的集合
     * @param single             true：单表      false：多表
     * @param transformRateFlag  转化率开启标志
     * @param selectTargetIsNull 需要计算转化率字段是否为空
     * @param selectTarget       需要计算转化率的字段
     */
    private void getFunnelItems(Map<String, ResultDataSeriesChartVO> linkedHashMapMap, JSONObject result, FieldAttrPojo chartClassifyPojo, List<FieldAttrPojo> fieldAttrPojoList, boolean single, boolean transformRateFlag, boolean selectTargetIsNull, FieldAttrPojo selectTarget,List<String> xAxis,List<String> xAxisKeys) {
        List<ItemPoJo> itemPoJoList = chartClassifyPojo.getItems();
        //根据统计结果过滤可见的漏斗图item
        itemPoJoList.removeIf(itemPoJo -> !xAxisKeys.contains(String.valueOf(itemPoJo.getValue())));
        if (CollectionUtils.isNotEmpty(itemPoJoList)){
            itemPoJoList.forEach(item ->{
                ResultDataSeriesChartVO resultDataSeriesChartVO = new ResultDataSeriesChartVO();
                resultDataSeriesChartVO.setName(item.getText());
                List<ResultDataSeriesChartVO> resultDataSeriesChartVOList = new ArrayList<>();
                for (FieldAttrPojo fieldAttrPojo : fieldAttrPojoList) {
                    ResultDataSeriesChartVO resultChartVO = new ResultDataSeriesChartVO();
                    resultChartVO.setName(fieldAttrPojo.getLabelName());
                    resultChartVO.setValue("0");
                    if (transformRateFlag && !selectTargetIsNull) {
                        if (single) {
                            if (Objects.equals(selectTarget.getAttr(), fieldAttrPojo.getAttr())) {
                                resultChartVO.setCode(fieldAttrPojo.getAttr());
                            }
                        } else {
                            if (Objects.equals(selectTarget.getAttr(), fieldAttrPojo.getOriginalAttr()) && Objects.equals(selectTarget.getFormId(), fieldAttrPojo.getFormId())) {
                                resultChartVO.setCode(fieldAttrPojo.getOriginalAttr());
                            }
                        }
                    }
                    // 因为漏斗图展示出来的字段名称需要前端进行特殊的拼接规则（根本因为是字段太长前端样式会有问题）
                    if (Objects.equals(fieldAttrPojo.getLabelName(), fieldAttrPojo.getLabel())) {
                        // 计算字段处理成false是因为计算字段本身就是用户自己输入的名称
                        if (Objects.equals(FieldTypeEnum.COMPUTED_FIELD.getType(), fieldAttrPojo.getFieldType())) {
                            resultChartVO.setLabelNameEditFlag(Boolean.TRUE);
                        } else {
                            resultChartVO.setLabelNameEditFlag(Boolean.FALSE);
                        }
                    } else {
                        resultChartVO.setLabelNameEditFlag(Boolean.TRUE);
                    }
                    resultDataSeriesChartVOList.add(resultChartVO);
                }
                resultDataSeriesChartVO.setResultDataSeriesChartVOList(resultDataSeriesChartVOList);
                linkedHashMapMap.put(String.valueOf(item.getValue()),resultDataSeriesChartVO);
            });
        }
        //过滤xAxis、xAxisKeys的值，确定最终要展示的item
        filterXaxisKey(xAxis,xAxisKeys,chartClassifyPojo);
        result.put("xAxis",linkedHashMapMap.values().stream().map(ResultDataSeriesChartVO::getName).collect(Collectors.toList()));
        result.put("xAxisKeys",linkedHashMapMap.keySet());
    }

    /**
     * 处理自定义下拉的值，因为只计算一个指标的转化率，所以只需要计算一个指标的数值总和就行
     *
     * @param totalBigDecimal       指标的总数值
     * @param selectTarget          选择转化率的字段
     * @param resultDataSeriesChart 单个指标的对象
     * @param index                 x轴key值的索引
     * @param xAxisKeys             x轴value值
     * @param linkedHashMapMap      关联表单设计阶段推进器的具体信息，也是根据这个值来构造返回值的. key: 对应x轴的key值， value：对应每一个维度的指标值
     * @return 指标的总数值（总值之和）
     */
    private BigDecimal handleFunnelValue(BigDecimal totalBigDecimal, FieldAttrPojo selectTarget, ResultDataSeriesChartVO resultDataSeriesChart,
                                         int index, List<String> xAxisKeys, Map<String, ResultDataSeriesChartVO> linkedHashMapMap) {
        if (CollectionUtils.isEmpty(xAxisKeys) || xAxisKeys.size() <= index) {
            return totalBigDecimal;
        }
        String xAxisKey = xAxisKeys.get(index);
        ResultDataSeriesChartVO temp = linkedHashMapMap.get(xAxisKey);
        boolean tempIsNull = Objects.isNull(temp);
        if (tempIsNull) {
            return totalBigDecimal;
        }
        if (!Objects.equals(selectTarget.getAttr(), resultDataSeriesChart.getCode())) {
            return totalBigDecimal;
        }
        return totalBigDecimal.add(new BigDecimal(resultDataSeriesChart.getValue()));
    }

    /**
     * 处理自定义下拉的转化率
     *
     * @param dataSeries      图需要的dataSeries数据内容
     * @param totalBigDecimal 指标的总金额
     * @param selectTarget    选中计算转换率的指标
     */
    private void handleFunnelTransFormRate(List<ResultDataSeriesChartVO> dataSeries, BigDecimal totalBigDecimal, FieldAttrPojo selectTarget) {
        BigDecimal totalValue = totalBigDecimal;
        for (ResultDataSeriesChartVO resultDataSeriesChartVO : dataSeries) {
            List<ResultDataSeriesChartVO> resultDataSeriesChartVOList = resultDataSeriesChartVO.getResultDataSeriesChartVOList();
            if (CollectionUtils.isEmpty(resultDataSeriesChartVOList)) {
                continue;
            }
            for (ResultDataSeriesChartVO dataSeriesChartVO : resultDataSeriesChartVOList) {
                if (!Objects.equals(selectTarget.getAttr(), dataSeriesChartVO.getCode())) {
                    continue;
                }
                BigDecimal value = new BigDecimal(dataSeriesChartVO.getValue());
                BigDecimal surplusValue = totalValue.subtract(value);
                BigDecimal zeroValue = new BigDecimal(0);
                String transFormRate;
                // 字段类型code 判断是否为计数类型
                JSONObject dataForm = dataSeriesChartVO.getDataForm();
                Integer accuracy = dataForm.getInteger("accuracy");
                Integer groupingUsed = dataForm.getInteger("groupingUsed");
                if (surplusValue.compareTo(zeroValue) > 0) {
                    String transFormValue = surplusValue.divide(totalValue, accuracy + 2, RoundingMode.HALF_UP).toString();
                    transFormRate = attrDecimalPrecisionHelper.getNumberFormat(transFormValue, accuracy, groupingUsed, 1);
                } else {
                    transFormRate = StringConstant.SHORT_BARS;
                }
                dataSeriesChartVO.setTransformRate(transFormRate);
                totalValue = surplusValue;
                break;
            }
        }
    }

    /**
     * 散点图 - 组装气泡大小值
     *
     * @param fieldAttrPojo 气泡大小的字段设置
     * @param scatterChartVO  返回对象
     * @param scatterValue  气泡大小的值
     * @author zyy
     * @date 2022/4/25
     * @version v1.0
     */
    private void setScatterChartValue(FieldAttrPojo fieldAttrPojo, ScatterChartVO scatterChartVO,String scatterValue) {
        int accuracy = fieldAttrPojo.getAccuracy() == null ? 0 : fieldAttrPojo.getAccuracy();
        Integer groupingUsed = fieldAttrPojo.getGroupingUsed();
        Integer numFormat = fieldAttrPojo.getNumFormat();
        NumFormatEnum numFormatEnum = NumFormatEnum.getByCode(numFormat);
        Integer percentUsed = fieldAttrPojo.getPercentUsed();
        // 用百分比，数据计算精度加两位，符号统一由前端渲染
        if (Objects.equals(percentUsed, 1)) {
            accuracy += 2;
        }
        // 计数不需要小数
        if (fieldAttrPojo.getFieldType().equals(FieldTypeEnum.COUNT.getType())) {
            accuracy = 0;
        }
        JSONObject dataFormSingle = new JSONObject();
        dataFormSingle.put("accuracy", accuracy);
        dataFormSingle.put("groupingUsed", groupingUsed);
        dataFormSingle.put("percentUsed", percentUsed);
        dataFormSingle.put("unit", numFormatEnum.getNoYuanUnit());
        try {
            scatterValue = StringUtil.formatDouble(Double.valueOf(scatterValue), accuracy, 1);
            // 百分比
            if (Objects.equals(percentUsed, 1) && !"".equals(scatterValue)) {
                scatterValue = String.valueOf(new BigDecimal(scatterValue).multiply(new BigDecimal("100")));
            }
            // 数值格式
            scatterValue = String.valueOf(ChartResultUtil.formatVal4Num(new BigDecimal(scatterValue), numFormatEnum, accuracy));
            // 格式化小数位
            scatterValue = StringUtil.formatDouble(Double.valueOf(scatterValue), accuracy, 1);
        } catch (Exception e) {
            scatterValue = "0";
        }
        scatterChartVO.setScatterSize(scatterValue);
        scatterChartVO.setAttr(fieldAttrPojo.getAttr());
        scatterChartVO.setDataForm(dataFormSingle);
        scatterChartVO.setName(fieldAttrPojo.getLabelName());
        scatterChartVO.setOriginalAttr(fieldAttrPojo.getOriginalAttr());
    }

}
